import 'dart:collection';

typedef void Handler<D>(D data);

class _EventListener {
  String _eventName;
  EventEmitter _emitter;
  bool _destroied;
  // 改动
  _EventListener(this._eventName, this._emitter);

  unregister() {
    this._emitter.off(this._eventName, this);
    this.destroy();
  }

  bool destroy() {
    if (this._destroied) {
      return false;
    }
    this._emitter = null;
    this._destroied = true;
    return true;
  }
}

class EventEmitter<E extends Map> {
  HashMap<String, List> _events = HashMap();
  EventEmitter();

  _EventListener on(String event, Handler handler) {
    if (this._events.isNotEmpty) {
      this._events[event] = [];
    }
    _EventListener listener = _EventListener(event, this);
    this._events[event].add(listener);
    return listener;
  }

  bool emit<D extends Map>(String event, D data) {
    if (this._events[event].isEmpty) {
      return false;
    }
    List<_EventListener> remains = [];
    for (var listener in this._events[event]) {
      if (listener.destroied) {
        continue;
      }
      if (listener) {
        remains.add(listener);
      }
      listener.handler(data);
    }
    if (remains.length != this._events[event].length) {
      this._events[event] = remains;
    }
    return true;
  }

  off(String event, _EventListener target) {
    if (this._events[event].isEmpty) {
      return false;
    }
    if (target != null) {
      for (var arr = this._events[event], i = 0; i < arr.length; i++) {
        var listener = arr[i];
        if (listener != target) {
          continue;
        }
        this._events[event] =
            this._events[event].where((l) => l != listener).toList();
        if (this._events[event].length == 0) {
          this._events.remove(event);
        }
      }
      print(target);
      print("Cannot find listenert of $event in $this --EventEmitter");
    } else {
      for (var arr = this._events[event], i = 0; i < arr.length; i++) {
        var listener = arr[i];
        this._events[event][i] = null;
        if (listener) {
          listener.destroy();
        }
      }
      this._events.remove(event);
    }
    return true;
  }

  removeAllListeners() {
    for (var name in this._events.entries) {
      var events = this._events[name];
      for (var arr = events, i = 0; i < arr.length; i++) {
        events.remove(i);
      }
      this._events.remove(name);
    }
  }
}
